﻿using ArmyAnt;

using Newtonsoft.Json;

using PlayMyLife.Definitions.StoryEvent;
using PlayMyLife.ModelLocal;

using System;
using System.Collections.Generic;

namespace ConfigEditor {
    public class EditorCore : ISettingSaverLoader {

        public static readonly ISettingSaverLoader Core = new EditorCore();

        private EditorCore() { }

        private IView? view;

        public IView? View {
            get {
                return view;
            }
            set {
                view = value;
                LoadFromDevFiles();
                view?.RefreshView();
            }
        }

        #region Places

        private readonly IDictionary<long, CreatePlaceEventArg> places = new Dictionary<long, CreatePlaceEventArg>();

        public CreatePlaceEventArg[] Places {
            get {
                var ret = new CreatePlaceEventArg[places.Count];
                places.Values.CopyTo(ret, 0);
                return ret;
            }
        }

        public bool AddPlace(CreatePlaceEventArg place) {
            if(place == null || places.ContainsKey(place.id) || idList.Contains(place.id)) {
                return false;
            }
            places.Add(place.id, place);
            idList.Add(place.id);
            return true;
        }

        public bool RemovePlace(long id) {
            return places.Remove(id) && idList.Remove(id);
        }

        public bool ChangePlaceData(CreatePlaceEventArg place) {
            if(place == null || !RemovePlace(place.id)) {
                return false;
            }
            places.Add(place.id, place);
            idList.Add(place.id);
            return true;
        }

        public void RefreshAllPlaces(CreatePlaceEventArg[]? places) {
            this.places.Clear();
            if(places != null) {
                foreach(var i in places) {
                    this.places.Add(i.id, i);
                    idList.Add(i.id);
                }
            }
        }

        #endregion Places

        #region Roles

        private readonly IDictionary<long, CreateRoleEventArg> roles = new Dictionary<long, CreateRoleEventArg>();

        public CreateRoleEventArg[] Roles {
            get {
                var ret = new CreateRoleEventArg[roles.Count];
                roles.Values.CopyTo(ret, 0);
                return ret;
            }
        }

        public bool AddRole(CreateRoleEventArg role) {
            if(role == null || roles.ContainsKey(role.id) || idList.Contains(role.id)) {
                return false;
            }
            roles.Add(role.id, role);
            idList.Add(role.id);
            return true;
        }

        public bool RemoveRole(long id) {
            return roles.Remove(id) && idList.Remove(id);
        }

        public bool ChangeRoleData(CreateRoleEventArg role) {
            if(role == null || !RemovePlace(role.id)) {
                return false;
            }
            roles.Add(role.id, role);
            idList.Add(role.id);
            return true;
        }

        public void RefreshAllRoles(CreateRoleEventArg[]? roles) {
            this.roles.Clear();
            if(roles != null) {
                foreach(var i in roles) {
                    this.roles.Add(i.id, i);
                    idList.Add(i.id);
                }
            }
        }

        #endregion Roles

        #region Save&Load Bridge

        public LocalConfigManager ConfigManager { get; private set; } = new LocalConfigManager();

        private readonly List<long> idList = new List<long>();

        public long RollFreeId() {
            long ret = 10001;
            while(idList.Contains(ret)) {
                ++ret;
            }
            return ret;
        }

        public bool SaveToDevFiles() {
            string placeDataFile = "places.json";
            devRootIO.SaveToFile(System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Places)), placeDataFile);
            string roleDataFile = "roles.json";
            devRootIO.SaveToFile(System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Roles)), roleDataFile);
            string eventDataFile = "events.json";
            devRootIO.SaveToFile(System.Text.Encoding.UTF8.GetBytes(ConfigManager.EventParseToText()), eventDataFile);
            string skillsDataFile = "skills.json";
            devRootIO.SaveToFile(System.Text.Encoding.UTF8.GetBytes(ConfigManager.SkillParseToText()), skillsDataFile);
            return true;
        }

        private bool LoadFromDevFiles() {
            devRootIO.MkdirIfNotExist();
            string placeDataFile = "places.json";
            if(devRootIO.ExistFile(placeDataFile)) {
                var data = devRootIO.LoadFromFile(placeDataFile);
                RefreshAllPlaces(JsonConvert.DeserializeObject<CreatePlaceEventArg[]>(System.Text.Encoding.UTF8.GetString(data)));
            } else {
                RefreshAllPlaces(null);
            }
            string roleDataFile = "roles.json";
            if(devRootIO.ExistFile(roleDataFile)) {
                var data = devRootIO.LoadFromFile(roleDataFile);
                RefreshAllRoles(JsonConvert.DeserializeObject<CreateRoleEventArg[]>(System.Text.Encoding.UTF8.GetString(data)));
            } else {
                RefreshAllRoles(null);
            }
            string eventDataFile = "events.json";
            string eventsStr = "{\"events\":[],\"args\":{}}";
            if(devRootIO.ExistFile(eventDataFile)) {
                eventsStr = System.Text.Encoding.UTF8.GetString(devRootIO.LoadFromFile(eventDataFile));
            }
            string skillsDataFile = "skills.json";
            string skillsStr = "{\"skills\":[]}";
            if(devRootIO.ExistFile(skillsDataFile)) {
                skillsStr = System.Text.Encoding.UTF8.GetString(devRootIO.LoadFromFile(skillsDataFile));
            }
            ConfigManager.InitFromText(eventsStr, skillsStr);
            idList.AddRange(ConfigManager.EventConfig.events.Keys);
            idList.AddRange(ConfigManager.SkillConfig.skills.GetPropCollection<long>("id"));
            return true;
        }

        public bool ExportToOutputFiles() {
            var exportConfigMgr = ConfigManager.DeepCopy();
            foreach(var i in Places) {
                exportConfigMgr.EventConfig.events.Add(i.id, new() {
                    id = i.id,
                    eventType = EventType.CreatePlace,
                    argsID = JsonConvert.SerializeObject(i),
                    withinEvents = Array.Empty<WithinEventData>()
                });
            }
            foreach(var i in Roles) {
                exportConfigMgr.EventConfig.events.Add(i.id, new() {
                    id = i.id,
                    eventType = EventType.CreateRole,
                    argsID = JsonConvert.SerializeObject(i),
                    withinEvents = Array.Empty<WithinEventData>()
                });
            }
            string eventDataFile = "events.json";
            outRootIO.SaveToFile(System.Text.Encoding.UTF8.GetBytes(exportConfigMgr.EventParseToText()), eventDataFile);
            string skillsDataFile = "skills.json";
            outRootIO.SaveToFile(System.Text.Encoding.UTF8.GetBytes(exportConfigMgr.SkillParseToText()), skillsDataFile);
            return false;
        }

        private readonly ArmyAnt.IO.IOManager devRootIO = new() { Root = System.IO.Path.GetFullPath(Environment.CurrentDirectory + "../../../../../../data/") };
        private readonly ArmyAnt.IO.IOManager outRootIO = new() { Root = System.IO.Path.GetFullPath(Environment.CurrentDirectory + "../../../../../../../Assets/PlayMyLifeCore/Config/") };

        #endregion Save&Load Bridge

        #region View Utilities

        public void F() {

        }

        #endregion View Utilities
    }
}
